package forum.server.controller;

import forum.server.domain.*;
import forum.server.exceptions.*;
import forum.server.persistence.DataManipulatorInt;

/**
 * This class handles all posts related operations.
 * Placed just above the Domain layer.
 * @author Mirsky
 *
 */
public class PostHandler {

	/**
	 * Stores currently logged user.
	 * If its' a guest session- null;
	 */
	private LoggedInUser loggedUser;

	/**
	 * Data persistent.
	 */
	private DataManipulatorInt dm;

	/**
	 * Search Engine interface.
	 */
	private SearchEngine se;

	/**
	 * Logger.
	 */
	private static MyLogger logger = MyLogger.getInstance();

	/**
	 * Constructor
	 * @param dm
	 * @param user
	 */
	public PostHandler(DataManipulatorInt dm, SearchEngine se, LoggedInUser user) {
		this.loggedUser = user;
		this.se = se;
		this.dm = dm;
	}

	/**
	 * Add a new post to the forum.
	 * @param header The header of the post
	 * @param pc The content of the post
	 * @return the created post
	 * @throws DatabaseException 
	 */
	public Post addPost(String header, PostContent pc) throws DatabaseException {
		Post tPost = this.loggedUser.addPost(header, pc, dm.generateNewPostId());
		int postId = this.dm.addPost(tPost);
		tPost.setPostId(postId);
		this.se.addData(tPost);
		logger.logInfo("Add Post: " + tPost.getPostId() + 
				" by " + this.loggedUser.getUsername());
		return tPost;
	}

	/**
	 * Modify an existing post.
	 * @param postId The ID of the post
	 * @param pc The new post content
	 * @return the modified post
	 * @throws UnauthorizedOpException in case user can't modify this post
	 * @throws NoSuchPostException in case postId doesn't exist
	 * @throws DatabaseException 
	 */
	public Post modifyPost(int postId, PostContent pc) 
	throws UnauthorizedOpException, NoSuchPostException, DatabaseException {
		Post tOldPost = this.dm.getPost(postId);
		if (tOldPost == null) {
			logger.logInfo("Modify Post: invalid postId " + postId);
			throw new NoSuchPostException("The requested post doen't exist.");			
		}
		this.se.removeData(tOldPost);
		Post tNewPost = this.loggedUser.modifyPost(tOldPost, pc);
		this.dm.modifyPost(postId, pc);
		this.se.addData(tNewPost);
		logger.logInfo("Modify Post: " + postId + " by " + 
				this.loggedUser.getUsername());
		return tNewPost;
	}
	
	/**
	 * Delete a post from the forum.
	 * @param postId - The ID of the post
	 * @throws UnauthorizedOpException - Thrown if the user can't delete the post.
	 * @throws NoSuchPostException - Thrown in case postId doesn't exist.
	 * @throws DatabaseException
	 */
	public void deletePost(int postId)
	throws UnauthorizedOpException, NoSuchPostException, DatabaseException {
		Post tPost = this.dm.getPost(postId);
		this.loggedUser.deletePost(tPost);
		for (Post post : this.dm.getReplies(postId)){
			this.dm.deletePost(post.getPostId());
			this.se.removeData(post);
		}
		this.dm.deletePost(postId);
		this.se.removeData(tPost);
	}

	/**
	 * Adds a reply to post.
	 * @param parentId The ID of the post adding reply to
	 * @param header The header of the reply
	 * @param pc The content of the reply
	 * @return the created reply
	 * @throws NoSuchPostException in case parentId doesn't exist
	 * @throws DatabaseException
	 */
	public Post replyToPost(int parentId, String header, PostContent pc) 
	throws NoSuchPostException, DatabaseException {
		Post parentPost = this.dm.getPost(parentId);
		if (parentPost == null) {
			logger.logInfo("Reply to postAdd reply to reply to non existent post: " + parentId);
			throw new NoSuchPostException("Parent post doesn't exist.");
		}
		logger.logInfo("Add reply: " + this.loggedUser.getUsername() + 
				" succefully replied to post: " + parentId);
		Post tPost = this.loggedUser.replyToPost(header, pc,this.dm.generateNewPostId(), parentId);
		int postId = this.dm.addReply(parentId, tPost);
		tPost.setPostId(postId);
		this.se.addData(tPost);
		return tPost;
	}

	/**
	 * Search thru posts by author.
	 * @param username Author's username
	 * @param from Date
	 * @param to Date
	 * @return SearchHit instance from the search engine
	 * @throws UserDoesntExistException in case useranem doesn't exist
	 * @throws InvalidSearchRangeException in case the range is invalid
	 */
	public SearchHit[] searchByAuthor(String username, int from, int to) 
	throws NoSuchUserException, InvalidSearchRangeException {
		logger.logInfo("Search by username for: " + username);
		return this.se.searchByAuthor(username, from, to);
	}

	/**
	 * Search thru post by content.
	 * @param phrase The serach string
	 * @param from Date
	 * @param to Date
	 * @return SearchHit instance from the search engine
	 * @throws InvalidSearchRangeException in case the range is invalid
	 */
	public SearchHit[] searchByContent(String phrase, int from, int to) 
	throws InvalidSearchRangeException {
		logger.logInfo("Search by phrase for: " + phrase);
		return this.se.searchByContent(phrase, from, to);
	}
}
